﻿using Furion;
using Furion.DataEncryption;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using BaseNet.Application.System.Authorize.Dto;
using BaseNet.Core.Consts;
using BaseNet.Core.Dtos;
using BaseNet.Core.SeedData;
using BaseNet.Core.SeedData.Dto;
using BaseNet.Core.Utils;
using BaseNet.Entity.System;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Furion.DynamicApiController;
using System.Threading;

namespace BaseNet.Application.System.Authorize
{
    /// <summary>
    /// 授权接口
    /// </summary>
    [ApiDescriptionSettings(Module = ModuleConsts.System)]
    public class AuthorizeService : IDynamicApiController
    {
        private readonly SqlSugarClient _db;
        private string _userId = string.Empty;
        public AuthorizeService(ISqlSugarRepository sqlSugarRepository)
        {
            _db = sqlSugarRepository.Context;
            _userId = App.User?.FindFirstValue("UserId");
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<string> Login([Required] LoginInput input)
        {
            using (var mutex = new Mutex(true, "/api/system/authorize/login/" + input.Account))
            {
                try
                {
                    if (!mutex.WaitOne(0, true))//若存在接口堵塞，则直接退出
                        throw Oops.Oh("当前接口存在正在进行的访问");

                    //获取加密后的密码
                    var encryptPassword = MD5Encryption.Encrypt(input.Password.Trim());

                    //判断用户名密码是否正确
                    var userEntity = await _db.Queryable<SysUserEntity>()
                        .Where(o => o.Account == input.Account.Trim() && o.Password == encryptPassword)
                        .FirstAsync();
                    if (userEntity == null)
                        throw Oops.Oh("用户名或密码不正确");

                    userEntity.LastLoginTime = DateTimeOffset.Now;
                    _db.ExtUpdateable(userEntity);

                    //生成token
                    var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
                    {
                        {"UserId",userEntity.Id },
                        {"Account",userEntity.Account }
                    }, 60 * 12);

                    //生成 刷新token(1天有效期)
                    var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken);

                    var httpContext = App.HttpContext;

                    //设置Swagger 自动登录
                    httpContext.SigninToSwagger(accessToken);

                    //设置响应报文头
                    httpContext.Response.Headers["access-token"] = accessToken;
                    httpContext.Response.Headers["x-access-token"] = refreshToken;

                    return accessToken;
                }
                finally
                {
                    try
                    {
                        mutex.ReleaseMutex();
                    }
                    catch (Exception) { }
                    mutex.Close();
                    mutex.Dispose();
                }
            }
        }

        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task ChangePwd([Required] ChangePwdInput input)
        {
            using (var mutex = new Mutex(true, "/api/system/authorize/changepwd/" + _userId))
            {
                try
                {
                    if (!mutex.WaitOne(0, true))//若存在接口堵塞，则直接退出
                        throw Oops.Oh("当前接口存在正在进行的访问");

                    //旧密码加密
                    var oldEncryptPassword = MD5Encryption.Encrypt(input.OldPassword.Trim());
                    //新密码加密
                    var newEncryptPassword = MD5Encryption.Encrypt(input.NewPassword.Trim());

                    //判断用户名密码是否正确
                    var userEntity = await _db.Queryable<SysUserEntity>()
                        .Where(o => o.Id == _userId && o.Password == oldEncryptPassword)
                        .FirstAsync();
                    if (userEntity == null)
                        throw Oops.Oh("原密码输入错误");
                    userEntity.Password = newEncryptPassword;
                    await _db.ExtUpdateableAsync(userEntity);

                }
                finally
                {
                    try
                    {
                        mutex.ReleaseMutex();
                    }
                    catch (Exception) { }
                    mutex.Close();
                    mutex.Dispose();
                }
            }
        }

        /// <summary>
        /// 获取当前用户菜单权限列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<SysMenuDto>> GetMenuList()
        {
            //获取用户菜单权限
            var userRoleIds = await _db.Queryable<SysUserRoleEntity>()
                .Where(o => o.UserId == _userId)
                .Select(o => o.RoleId)
                .Distinct()
                .ToListAsync();

            var roleMenuIds = await _db.Queryable<SysRoleMenuEntity>()
                .Where(o => userRoleIds.Contains(o.RoleId))
                .Select(o => o.MenuId)
                .Distinct()
                .ToListAsync();

            var list = SysMenuSeedData.GetList().FindAll(o => roleMenuIds.Contains(o.Id));
            list.ForEach(item =>
            {
                item.Href = $"{item.Href}?v=" + RndHelper.RndNum(6);
            });

            var menuList = SysMenuSeedData.GetTreeList(list);

            return menuList;
        }

        /// <summary>
        /// 获取当前用户详情
        /// </summary>
        /// <returns></returns>
        public async Task<CurrentDto> GerCurrentInfo()
        {
            //获取当前用户信息
            var output = await _db.Queryable<SysUserEntity>()
                .Where(o => o.Id == _userId)
                .Select<CurrentDto>()
                .FirstAsync();

            var userRoleIds = await _db.Queryable<SysUserRoleEntity>()
                .Where(o => o.UserId == _userId)
                .Select(o => o.RoleId)
                .Distinct()
                .ToListAsync();

            var roleList = await _db.Queryable<SysRoleEntity>()
                .Where(o => userRoleIds.Contains(o.Id))
                .Select(o => o.Name)
                .ToListAsync();

            output.RoleNames = string.Join(",", roleList);

            return output;
        }

    }
}
